#pragma once

#include <iostream>
#include <cstdio>
#include <string>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>

const int gdefaultid = -1;
//gdefaultid：初始化为 -1，用作共享内存标识符（shmid）的默认值。在后续代码里，
//若 shmid 为 -1，就表明共享内存尚未成功创建或获取
const int gsize = 4096;
//设定共享内存段的大小为 4096 字节
const std::string pathname = ".";
//指定为当前目录 "."，这是 ftok 函数所需的路径名，ftok 会依据此路径名和项目 ID 生成一个键值（key）
const int projid = 0x65;
//ftok 函数所需的项目 ID
const int gmode = 0666;

#define ERR_EXIT(m) \
    do              \
    {               \
        perror(m);\   
        exit(EXIT_FAILURE);\
    }while(0)
//ERR_EXIT 是一个宏，其用途是处理错误情况。
//do {... } while(0) 这种结构保证了宏在被使用时，无论是否处于 if、for 等语句块里，都能正常运行。
//perror(m) 会把错误信息输出到标准错误流，同时显示 m 这个自定义的错误提示。
//exit(EXIT_FAILURE) 会让程序终止并返回一个表示失败的状态码

class Shm
{
private:
 //创建的一定要是个全新的共享内存
 void CreateHelper(int flg)
 {
     key_t k = ftok(pathname.c_str(), projid);
     // pathname 和 projid 生成一个键值 k
     if(k < 0)
     {
         ERR_EXIT("ftok");
         // ftok 函数调用失败，会返回一个小于 0 的值，此时调用 ERR_EXIT("ftok") 输出错误信息并终止程序
     }
     printf("key: 0x%x  ", k);//ftok 调用成功，就打印生成的键值 k
     //_shmid = shmget(k, _size, IPC_CREAT | IPC_EXCL | 0666);//也要有权限设置
     _shmid = shmget(k, _size, flg);
     //调用 shmget 函数来创建共享内存段。IPC_CREAT 表示若共享内存段不存在就创建它，
     //IPC_EXCL 表示若共享内存段已经存在则返回错误
     if(_shmid < 0)
     {
         ERR_EXIT("shmget");
         // shmget 函数调用失败，会返回一个小于 0 的值，此时调用 ERR_EXIT("shmget") 输出错误信息并终止程序
     }
     printf("shmid:%d\n  ", _shmid);
     //调用成功，就打印创建的共享内存段的标识符 _shmid
 }
public:
    Shm():_shmid(gdefaultid), _size(gsize), _start_mem(nullptr)
    //_shmid 用于存储共享内存标识符，_size 用于存储共享内存的大小
    {

    }
    void Creat()
    {
        CreateHelper( IPC_CREAT | IPC_EXCL | gmode);
    }
   

    //获取
    void Get()
    {
        CreateHelper( IPC_CREAT );
    }


    void Destroy()
    {
        if(_shmid == gdefaultid) return;
        // 检查共享内存标识符是否为默认值（即未创建共享内存）
        int n = shmctl(_shmid, IPC_RMID, nullptr);
        // 调用 shmctl 函数，尝试删除共享内存段
        if(n > 0)
        {
            printf("shmctl delete shm: %d sucess!\n", _shmid);
            //表示删除成功，输出成功信息
        }
        else
        {
            ERR_EXIT("shmctl");
            //删除失败，调用 ERR_EXIT 宏处理错误
        }
    }
    void Attach()
    {
        _start_mem = shmat(_shmid,nullptr,0);
        if((long long)_start_mem < 0)
        //在进行类型转换为 long long 后就是小于 0 的值
        {
            ERR_EXIT("shmat");
        }
        printf("attach succcess\n");
    }
    void *VirturalAddr()
    {
        printf("*VirturalAddr: %p\n", _start_mem);
        //使用 printf 函数，以指针格式（%p）打印出共享内存的虚拟地址
        return _start_mem;
        //返回指向共享内存起始地址的指针 _start_mem，
        //供其他函数使用该指针来操作共享内存中的数据
    }
private:
    int _shmid;
    int _size;
    void *_start_mem;
};

